One of the standard compiler optimizations is a technique of local commoning. In this particular optimization, the compiler aims to reuse an already computed value in a register instead of redoing the computation within the scope of an extended basic block. This reuse can only be performed safely when the register being reused contains the same value as would have been produced if the expression pertaining to the computed value had been evaluated. In addition to typical constraints, including checking for kills and other constraints, that must be checked to perform local commoning for non-volatile variables, there are additional constraints that must be checked to common volatile variables.
Compiler optimization of volatile fields in a managed runtime environment, including Java®, is subject to more constraints than non-volatile fields. The reason for additional constraints is because volatile variables accesses act as both memory barriers and loads or stores of memory.